/**
 * websocket插件
 */
import util from './utils.holdtime.js'

function WSocket (url, conf) {
  this._settings = {
    open () {},
    close () {},
    message () {},
    error () {},
    events: {},
    isDebug: false,
    timeout: 60000, // 默认60秒
    autoConnect: true, // 自动连接
    eventField: 'name' // 事件类型字段名称
  }

  Object.assign(this._settings, conf)
  // 调试日志
  this.log = {
    d: (...msg) => {
      if (this._settings.isDebug) {
        console.debug(url + 'websocket:', ...msg)
      }
    }
  }
  // 心跳机制
  let timeoutObj = null
  this.heartCheck = {
    start: () => {
      timeoutObj = setTimeout(() => {
        this.log.d('发送心跳...')
        this.send('HeartBeat')
      }, this._settings.timeout)
    },
    stop: () => {
      this.log.d('停止心跳...')
      clearTimeout(timeoutObj)
    },
    reset: () => {
      this.log.d('刷新心跳...')
      clearTimeout(timeoutObj)
      this.heartCheck.start()
    }
  }
  // 开启断线重连
  this.isReConnect = true
  if (this._settings.autoConnect) {
    this.connect(url)
  }
}

WSocket.prototype.connect = function (url) {
  if (this.ws && this.ws.readyState === this.ws.OPEN) {
    return
  }

  let ws = 'WebSocket' in window ? new WebSocket(url) :
    'MozWebSocket' in window ? new MozWebSocket(url) :
      console.error('当前浏览器版本太低，不支持websocket!')

  // 连接成功事件
  ws.onopen = () => {
    this.log.d('连接成功...')
    this.heartCheck.start()
    if (util.isFunction(this._settings.open)) {
      this._settings.open.call(this)
    }
  }
  // 接收消息事件
  ws.onmessage = evt => {
    let d = JSON.parse(evt.data)
    this.log.d('<===', d)
    this.heartCheck.reset()
    if (d === 'HeartBeat') return
    if (util.isFunction(this._settings.message)) {
      this._settings.message.call(this, evt)
    }
    let h = this._settings.events[d[this._settings.eventField]]
    if (h) {
      h.call(this, d)
    }
  }
  // 连接关闭事件
  ws.onclose = () => {
    if (this.isReConnect) {
      this.log.d('启动重连...')
      this.connect(url)
    }
    if (util.isFunction(this._settings.close)) {
      this._settings.close.call(this)
    }
  }
  // 异常事件
  ws.onerror = e => {
    console.error(e)
    if (util.isFunction(this._settings.error)) {
      this._settings.error.call(this, e)
    }
  }
  this.ws = ws
}

WSocket.prototype.send = function (data) {
  this.log.d('===>', data)
  return this.ws.send(JSON.stringify(data))
}

WSocket.prototype.close = function () {
  this.heartCheck.stop()
  this.isReConnect = false
  if (this.ws) this.ws.close()
  this.ws = null
}

export default WSocket
